package chat.server.statemachine.mutex;

import chat.State;
import chat.server.ChatServerState;
import chat.statemachine.AbstractContent;
import chat.statemachine.AlgorithmActionInvocationException;

import java.io.IOException;
import java.lang.Math;
/**
 * 
 * @author Baptiste Lafontaine
 *
 */
public class AlgorithmMutexActions {
	private static boolean debug = false;
	/**
	 * 
	 * @param state
	 * @param content
	 * @return
	 * @throws AlgorithmActionInvocationException
	 */
	public static Object receiveTokenContent(final State state,
			final AbstractContent content)
	throws AlgorithmActionInvocationException {
		ChatServerState sstate = null;
		if (content == null) {
			throw new IllegalArgumentException(
			"Try executing action with null content");
		}
		if (state == null) {
			throw new IllegalArgumentException(
			"Try executing action with null state");
		}
		if (state instanceof ChatServerState) {
			sstate = (ChatServerState) state;
		} else {
			throw new IllegalArgumentException(
					"Try executing action with state of wrong type ("
					+ state.getClass().getName()
					+ " instead of ChatServerState");
		}
		if (content instanceof MutexTokenContent) {
			MutexTokenContent mtc = (MutexTokenContent) content;
			System.out.println("MutexToken received");
			sstate.hasToken = true;
			sstate.mutexTokenContent = mtc;
			System.out.println("Server " + sstate.identity + " has token");
		} 
		else {
			throw new AlgorithmActionInvocationException(
					"Error when executing action: not right message type ("
					+ content.getClass().getName() + ")");
		}
		return null;
	}
	/**
	 * Function called everytime a MutexAsk token is received.
	 * @param state
	 * @param content
	 * @return nothing
	 * @throws AlgorithmActionInvocationException
	 */
	public static Object receiveMutexAskContent(final State state,
			final AbstractContent content)
	throws AlgorithmActionInvocationException {
		ChatServerState sstate = null;
		if (content == null) {
			throw new IllegalArgumentException(
			"Try executing action with null content");
		}
		if (state == null) {
			throw new IllegalArgumentException(
			"Try executing action with null state");
		}
		if (state instanceof ChatServerState) {
			sstate = (ChatServerState) state;
		} else {
			throw new IllegalArgumentException(
					"Try executing action with state of wrong type ("
					+ state.getClass().getName()
					+ " instead of ChatServerState");
		}
		if (content instanceof MutexAskContent) {
			MutexAskContent mac = (MutexAskContent) content;
			System.out.println("Ask token from " + mac.getFrom());
			Integer demq = sstate.dem.get(mac.getFrom());
			if (demq != null) {
				sstate.dem.put(mac.getFrom(), Math.max(sstate.ns,demq));
			}
			else {
				sstate.dem.put(mac.getFrom(), sstate.ns);
			}
			if (sstate.hasToken) {
				/* Code "a la sortie de la section critique" */
				/* On prend l'hypoth�se que l'on est plus dans la section critique */

				/* jet[p] = ns */
				System.out.println("I have token, send it!");
				
				int q = sstate.identity + 1;
				if (q >= sstate.numOfNeigh) {
					q = 0;
				}
				while (q != sstate.identity) {
					if (debug) { System.out.println("q:" + q + "   dem[q]:" + sstate.dem.get(q) + "   mutexTokenContent(q):" + sstate.mutexTokenContent.getContent(q)); }
					if (((sstate.dem.get(q) == null ? 0 : sstate.dem.get(q)) > sstate.mutexTokenContent.getContent(q)) && (sstate.hasToken)) {
						try {
							sstate.server.sendToAServer(q,AlgorithmMutex.TOKEN_MUTEX.getActionIndex(),sstate.mutexTokenContent);
							sstate.hasToken=false;
							System.out.println("Server " + sstate.identity + " left token");
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
                    q++;
                    if (q >= sstate.numOfNeigh + 1) {
                        q = 0;
                    }
				}
			}
		} 
		else {
			throw new AlgorithmActionInvocationException(
					"Error when executing action: not right message type ("
					+ content.getClass().getName() + ")");
		}
		return null;
	}
}
